#include "Renderer.h"
#include "opencv2/opencv.hpp"
#include "OpenCLGL_Util.h"

HandModelRenderer::HandModelRenderer()
{
	// Create Constant Values
	/*x+- 12.8 ; y+-7.48*/

	screen_width = SIZE_IMAGE_PARTICLE_WIDTH;
	screen_height = SIZE_IMAGE_PARTICLE_HEIGHT*NUM_TOTAL_PARTICLES;

	particle_screen_width = SIZE_IMAGE_PARTICLE_WIDTH;
	particle_screen_height = SIZE_IMAGE_PARTICLE_HEIGHT;

	pixel_per_mm = PIXEL_PER_MM;  // Ti le giua so pixel voi kich thuoc thuc cua tay
	mm_per_Pixel = 0.700035f;

	frushtum_focal = KINECT_DEPTH_NOMINAL_FOCAL_LENGTH_IN_PIXELS;//(pixels) ~ 400mm : 
	frushtum_far = 1999.9f;//(pixels) ~ 1400mm
}

HandModelRenderer::~HandModelRenderer()
{

}

void HandModelRenderer::initializePixelBufs()
{
	int DATA_SIZE = screen_width*screen_height*sizeof(float);
	glGenBuffersARB(1, &obsDepthBuffer);
	glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, obsDepthBuffer);
	glBufferDataARB(GL_PIXEL_PACK_BUFFER_ARB, DATA_SIZE, 0, GL_STREAM_READ_ARB);
	glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, 0);
	glGenBuffersARB(1, &obsSkinBuffer);
	glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, obsSkinBuffer);
	glBufferDataARB(GL_PIXEL_PACK_BUFFER_ARB, DATA_SIZE, 0, GL_STREAM_READ_ARB);
	glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, 0);
	glGenBuffersARB(1, &renBuffer);
	glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, renBuffer);
	glBufferDataARB(GL_PIXEL_PACK_BUFFER_ARB, DATA_SIZE, 0, GL_STREAM_READ_ARB);
	glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, 0);

	glGenRenderbuffers(1, &renderFrameBuffer);
	glBindRenderbuffer(GL_RENDERBUFFER, renderFrameBuffer);
	glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, screen_width, screen_height);
	glBindRenderbuffer(GL_RENDERBUFFER, 0);

	glGenFramebuffers( 1 , &frameBuffer );
	glBindFramebuffer( GL_FRAMEBUFFER , frameBuffer );
	glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, renderFrameBuffer);
	GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
	if(status == GL_FRAMEBUFFER_COMPLETE) printf("setting ok \n");
	glBindFramebuffer( GL_FRAMEBUFFER , 0 );
}

void HandModelRenderer::initializeGLContext()
{
	if (!glfwInit())
		exit(EXIT_FAILURE);
	window = glfwCreateWindow(256*2,256, "Hand Example", NULL, NULL);
	
	//if (!SHOW_DEBUG)glfwHideWindow(window);
	 glfwSetWindowPos(window,0,0);
	if (!window)
	{
		glfwTerminate();
		exit(EXIT_FAILURE);
	}
	glfwMakeContextCurrent(window);
	glEnable( GL_DEPTH_TEST );
	glewInit();

	initializePixelBufs();
	
	rHand.generateVertexBuffers();
}

void HandModelRenderer::renderHandModelGL()
{
	glMatrixMode(GL_PROJECTION);glLoadIdentity();
	glFrustum(-128,128,-128,128,frushtum_focal,frushtum_far);
	double rotY = atan(rHand.wirst_position[0]/-rHand.wirst_position[2])*57.2957795;
	double rotX = atan(rHand.wirst_position[1]/rHand.wirst_position[2])*57.2957795;
	glRotated(rotY,0,1,0);
	glRotated(rotX,1,0,0);
	glMatrixMode(GL_MODELVIEW);glLoadIdentity();
	rHand.drawHand();// draw hand data
}

void HandModelRenderer::renderHandModelGL_Comparing(HypothesisX observeModel,HypothesisX tempModel)
{
	glColorMask(1,1,1,1);     // Disable color, it's useless, we only want depth.
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 
	glViewport(0,0,256,256);glLoadIdentity();
	rHand.handDOFs = observeModel.dofData;
	renderHandModelGL();

	glViewport(256,0,256,256);glLoadIdentity();
	rHand.handDOFs = tempModel.dofData;
	renderHandModelGL();

	glfwSwapBuffers(window);
	glfwPollEvents();
}

void HandModelRenderer::renderMultiModelGL(std::vector<HypothesisX> &hypos)
{
	glBindFramebuffer( GL_FRAMEBUFFER , frameBuffer );
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	glColorMask(0,0,0,0);     // Disable color, it's useless, we only want depth.
	glDepthMask(GL_TRUE);     // Ask z writing
	
	int stepW =	particle_screen_width;
	int stepH = particle_screen_height;
	for (int i=0;	i<hypos.size();	i++){
		/*SPLIT MODELS TO VIEWPORTs*/
		rHand.handDOFs = hypos[i].dofData;
		glViewport(0,i*stepH,stepW,stepH);
		renderHandModelGL();	
	}
	glBindFramebuffer( GL_FRAMEBUFFER , 0 );
	glUseProgram(0);
}

void HandModelRenderer::putDepthToBuf(GLuint & buffer)
{
	glBindFramebuffer( GL_FRAMEBUFFER , frameBuffer );
	glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, buffer);
	glReadBuffer(GL_DEPTH_ATTACHMENT); // Lay buffer phia truoc
	glReadPixels(0, 0, screen_width, screen_height, GL_DEPTH_COMPONENT, GL_FLOAT,0); // Lay do sau
	glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, 0);
	glBindFramebuffer( GL_FRAMEBUFFER , 0 );
}

void HandModelRenderer::terminateGLContext()
{
	glfwDestroyWindow(window);
	glfwTerminate();
	exit(EXIT_SUCCESS);
}